接下來的內容十分困難,如果有誤請見諒。一般來說,在遇到併發問題,最常遇到的困擾是多個不同的執行緒需要讀寫相同的資料,這時候發生競爭,就會產生意想不到的結果。舉個例子來說,主廚正在準備餐點,嚐了一口後覺得不夠鹹,一聲令下叫學徒幫忙加一匙鹽,結果學徒A跟學徒B接收到命令後開始加鹽程序,結果不小心加到同一道菜,於是乎客人覺得太鹹了,導致主廚被開除的人倫悲劇(我到底在說什麼…..
一般來說再處理併發有幾種方式
Lock
這應該是大家比較熟悉的方式,我們可以在執行緒讀寫時幫資料加上鎖,當執行完成時才解開來讓其他的執行緒能夠使用。
class LockSample
{
private readonly object lockObject = new object();
public void UpdateStatus(Sample sample)
{
lock(lockObject)
{
sample.Status = !sample.Status;
}
}
}
像上面的範例就是一段修改狀態的程式,並且將執行緒鎖住。使用鎖的好處是直覺簡單,在鎖失效之前都能保證只有單一執行緒能夠進行讀寫,同時也代表了其他的執行緒需要等到解鎖才能夠繼續作業,為了解決一個問題反而可能衍生其他問題問題像是DeadLock之類的,不過只要能夠確保沒有問題Lock仍然是一個簡單易用的好方法。
Software Transactional Memory
第二個方法是普遍的函數式語言常用的,類似資料庫中的交易,搭配函數式的一些特性讓併發容易處理,以兩個執行緒(A/B)需讀取並更新相同欄位(ColumnA)為例,需要歷經以下過程
是不是跟資料庫的交易很像呢?(如果失敗就rollback)
Actor model
最後一個模型是將作業抽象成物件導向中不同的對象,並且搭配函數導向中的一些觀念設計的模型,我們稱每個對象都是一個Actor
透過訊息方式傳遞資訊的意思是,如果兩個Actor需要共同的狀態,那就複製一份過去,每個Actor都保有自己所需的資訊,就可以避免競爭問題。Actor model其實主要是用在分散式系統,不同機器之間依靠通訊協作,如果放在本機上就像是多個執行緒之間依靠通訊共享資訊。是不是非常抽象呢?明天我們會對他有近一步介紹。